#include <sdk.h>
#include "CommitBrowser.h"
#include "FileExplorerUpdater.h"
#include <wx/xrc/xmlres.h>

BEGIN_EVENT_TABLE( CommitBrowser, wxDialog )
  EVT_COMMAND( 0, wxEVT_NOTIFY_UPDATE_COMPLETE, CommitBrowser::OnUpdateComplete )
  EVT_COMMAND( 0, wxEVT_NOTIFY_COMMITS_UPDATE_COMPLETE, CommitBrowser::OnCommitsUpdateComplete )
  EVT_LIST_ITEM_SELECTED( XRCID( "ID_COMMITLIST" ), CommitBrowser::OnListItemSelected )
  EVT_CHOICE( XRCID( "ID_BRANCH_CHOICE" ), CommitBrowser::OnBranchSelected )
  EVT_CHECKBOX( XRCID( "ID_CHECK_COMMIT_AFTER" ), CommitBrowser::OnCheckCommitAfterDate )
  EVT_CHECKBOX( XRCID( "ID_CHECK_COMMIT_BEFORE" ), CommitBrowser::OnCheckCommitBeforeDate )
  EVT_CHECKBOX( XRCID( "ID_CHECK_START_COMMIT" ), CommitBrowser::OnCheckCommitStart )
  EVT_CHECKBOX( XRCID( "ID_CHECK_END_COMMIT" ), CommitBrowser::OnCheckCommitEnd )
END_EVENT_TABLE()

CommitBrowser::CommitBrowser( wxWindow* parent, const wxString& repo_path, const wxString &repo_type, const wxString &files ) {
  wxXmlResource* xml_res = wxXmlResource::Get();
  wxString resPath = ConfigManager::GetDataFolder() + _T( "/CommitBrowser.xrc" );
  xml_res->Load( resPath );
  if( !xml_res->LoadObject( this, parent, _T( "CommitBrowser" ), _T( "wxDialog" ) ) ) {
    return;
  }
  StaticText1 = ( wxStaticText* )FindWindow( XRCID( "ID_STATICTEXT1" ) );
  Choice1 = ( wxChoice* )FindWindow( XRCID( "ID_BRANCH_CHOICE" ) );
  CommitList = ( wxListCtrl* )FindWindow( XRCID( "ID_COMMITLIST" ) );
  TextCtrl1 = ( wxTextCtrl* )FindWindow( XRCID( "ID_COMMIT_MESSAGE" ) );
  ButtonMore = ( wxButton* )FindWindow( XRCID( "ID_BUTTON_MORE" ) );
  CommitStatus = ( wxStaticText* )FindWindow( XRCID( "ID_COMMIT_STATUS" ) );
  Button1 = ( wxButton* )FindWindow( XRCID( "ID_CANCEL" ) );
  Button2 = ( wxButton* )FindWindow( XRCID( "ID_BROWSE_COMMIT" ) );
  CheckStartCommit = ( wxCheckBox* )FindWindow( XRCID( "ID_CHECK_START_COMMIT" ) );
  StartCommit = ( wxTextCtrl* )FindWindow( XRCID( "ID_START_COMMIT" ) );
  CheckEndCommit = ( wxCheckBox* )FindWindow( XRCID( "ID_CHECK_END_COMMIT" ) );
  EndCommit = ( wxTextCtrl* )FindWindow( XRCID( "ID_END_COMMIT" ) );
  CheckAfterDate = ( wxCheckBox* )FindWindow( XRCID( "ID_CHECK_COMMIT_AFTER" ) );
  AfterDate = ( wxDatePickerCtrl* )FindWindow( XRCID( "ID_COMMIT_AFTER_DATE" ) );
  CheckBeforeDate = ( wxCheckBox* )FindWindow( XRCID( "ID_CHECK_COMMIT_BEFORE" ) );
  BeforeDate = ( wxDatePickerCtrl* )FindWindow( XRCID( "ID_COMMIT_BEFORE_DATE" ) );
  Grep = ( wxTextCtrl* )FindWindow( XRCID( "ID_GREP_ENTRY" ) );
  FileEntry = ( wxTextCtrl* )FindWindow( XRCID( "ID_FILE_ENTRY" ) );
  Connect( XRCID( "ID_SEARCH_BUTTON" ), wxEVT_COMMAND_BUTTON_CLICKED, ( wxObjectEventFunction )&CommitBrowser::OnSearch );
  Connect( XRCID( "ID_CANCEL" ), wxEVT_COMMAND_BUTTON_CLICKED, ( wxObjectEventFunction )&CommitBrowser::OnButton1Click );
  Connect( XRCID( "ID_BROWSE_COMMIT" ), wxEVT_COMMAND_BUTTON_CLICKED, ( wxObjectEventFunction )&CommitBrowser::OnButton2Click );
  Connect( XRCID( "ID_BUTTON_MORE" ), wxEVT_COMMAND_BUTTON_CLICKED, ( wxObjectEventFunction )&CommitBrowser::OnButtonMore );
  m_autofetch_count = 0;
  m_repo_path = repo_path;
  m_repo_type = repo_type;
  CommitList->InsertColumn( 0, _T( "ID" ) );
  CommitList->InsertColumn( 1, _T( "Author" ) );
  CommitList->InsertColumn( 2, _T( "Date" ) );
  CommitList->InsertColumn( 3, _T( "Message" ) );
  ButtonMore->Disable();
  Button2->Disable();
  TextCtrl1->Clear();
  this->SetSize( 600, 500 );
  m_rev_fetch_amt[_T( "SVN" )] = 20;
  m_rev_fetch_amt[_T( "GIT" )] = 100;
  m_rev_fetch_amt[_T( "BZR" )] = 100;
  m_rev_fetch_amt[_T( "Hg" )] = 100;
  FileEntry->SetValue( files );
  m_updater_commits = new CommitUpdater( this, m_repo_path, m_repo_type );
  m_updater = new CommitUpdater( this, m_repo_path, m_repo_type );
  m_updater->Update( _T( "BRANCHES" ) );
}

CommitBrowser::~CommitBrowser() {
}

wxString CommitBrowser::GetRepoBranch() {
  if( Choice1->GetSelection() >= 0 ) {
    return Choice1->GetString( Choice1->GetSelection() );
  } else {
    return wxEmptyString;
  }
}

wxString CommitBrowser::GetSelectedCommit() {
  long item = CommitList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
  if( item >= 0 ) {
    wxListItem li;
    li.SetId( item );
    li.SetColumn( 0 );
    CommitList->GetItem( li );
    return li.GetText();
  }
  return wxEmptyString;
}

void CommitBrowser::OnSearch( wxCommandEvent& ) {
  wxString br = GetRepoBranch();
  CommitsUpdaterQueue( _T( "COMMITS:" ) + br );
  CommitList->DeleteAllItems();
  TextCtrl1->Clear();
  Button2->Disable();
  ButtonMore->Disable();
  CommitStatus->SetLabel( _T( "Loading commits..." ) );
}

void CommitBrowser::OnButton1Click( wxCommandEvent& ) {
  EndModal( wxID_CANCEL );
}

void CommitBrowser::OnButton2Click( wxCommandEvent& ) {
  EndModal( wxID_OK );
}

void CommitBrowser::OnCheckCommitAfterDate( wxCommandEvent &event ) {
  AfterDate->Enable( event.GetInt() );
}

void CommitBrowser::OnCheckCommitBeforeDate( wxCommandEvent &event ) {
  BeforeDate->Enable( event.GetInt() );
}

void CommitBrowser::OnCheckCommitStart( wxCommandEvent &event ) {
  StartCommit->Enable( event.GetInt() );
}

void CommitBrowser::OnCheckCommitEnd( wxCommandEvent &event ) {
  EndCommit->Enable( event.GetInt() );
}

void CommitBrowser::OnButtonMore( wxCommandEvent& ) {
  CommitsUpdaterQueue( _T( "CONTINUE" ) );
  ButtonMore->Disable();
  CommitStatus->SetLabel( _T( "Loading commits..." ) );
}

void CommitBrowser::CommitsUpdaterQueue( const wxString &cmd ) {
  if( m_updater_commits->IsRunning() ) {
    m_update_commits_queue = cmd;
  } else {
    m_update_commits_queue = wxEmptyString;
    CommitUpdater* cu = m_updater_commits;
    if( cmd == _T( "CONTINUE" ) ) {
      m_updater_commits = new CommitUpdater( *m_updater_commits );
      m_updater_commits->UpdateContinueCommitRetrieve();
    } else {
      m_autofetch_count = 0;
      m_updater_commits = new CommitUpdater( this, m_repo_path, m_repo_type );
      m_updater_commits->Update( cmd, GetRepoBranch(), GetCommitOptions() );
    }
    delete cu;
  }
}

void CommitBrowser::OnListItemSelected( wxListEvent &event ) {
  wxListItem li = event.GetItem();
  wxString id = li.GetText();
  Button2->Enable();
  TextCtrl1->Clear();
  if( m_updater == 0 && id != wxEmptyString ) {
    m_updater = new CommitUpdater( this, m_repo_path, m_repo_type );
    m_updater->Update( _T( "DETAIL:" ) + id );
  } else {
    m_update_queue = _T( "DETAIL:" ) + id;
  }
}

CommitUpdaterOptions CommitBrowser::GetCommitOptions() {
  wxString e( wxEmptyString );
  return CommitUpdaterOptions( FileEntry->GetValue(),
                               Grep->GetValue(),
                               CheckStartCommit->IsChecked() ? StartCommit->GetValue() : e,
                               CheckEndCommit->IsChecked() ? EndCommit->GetValue() : e,
                               CheckBeforeDate->IsChecked() ? wxString( BeforeDate->GetValue().FormatISODate() ) : e,
                               CheckAfterDate->IsChecked() ? wxString( AfterDate->GetValue().FormatISODate() ) : e,
                               m_repo_type != wxEmptyString ? m_rev_fetch_amt[m_repo_type] : 0
                             );
}

void CommitBrowser::OnBranchSelected( wxCommandEvent & ) {
  wxString br = Choice1->GetString( Choice1->GetSelection() );
  CommitsUpdaterQueue( _T( "COMMITS:" ) + br );
  CommitList->DeleteAllItems();
  ButtonMore->Disable();
  Button2->Disable();
  CommitStatus->SetLabel( _T( "Loading commits..." ) );
}

void CommitBrowser::OnCommitsUpdateComplete( wxCommandEvent& ) {
  if( m_updater_commits == 0 ) {
    return;
  }
  m_updater_commits->Wait();
  if( m_updater_commits->m_what.StartsWith( _T( "COMMITS:" ) ) ) {
    wxString branch = m_updater_commits->m_what.AfterFirst( _T( ':' ) );
    m_autofetch_count += m_updater_commits->m_commits.size();
    for( unsigned int i = 0; i < m_updater_commits->m_commits.size(); ++i ) {
      CommitEntry ce = m_updater_commits->m_commits[i];
      wxListItem li;
      li.SetId( CommitList->GetItemCount() );
      int pos = CommitList->InsertItem( li );
      CommitList->SetItem( pos, 0, ce.id );
      CommitList->SetItem( pos, 1, ce.author );
      CommitList->SetItem( pos, 2, ce.date );
      CommitList->SetItem( pos, 3, ce.message );
    }
    CommitList->SetColumnWidth( 2, wxLIST_AUTOSIZE );
    CommitList->SetColumnWidth( 3, wxLIST_AUTOSIZE );
    if( m_updater_commits->m_retrieved_all ) {
      m_autofetch_count = 0;
      ButtonMore->Disable();
    } else {
      if( m_autofetch_count < m_rev_fetch_amt[m_repo_type] ) {
        CommitsUpdaterQueue( _T( "CONTINUE" ) );
      } else {
        m_autofetch_count = 0;
        ButtonMore->Enable();
      }
    }
    if( CommitList->GetItemCount() != 1 ) {
      CommitStatus->SetLabel( wxString::Format( _T( "Showing %i commits" ), CommitList->GetItemCount() ) );
    } else
    { CommitStatus->SetLabel( _T( "Showing 1 commit" ) ); }
  }
  if( m_update_commits_queue != wxEmptyString ) {
    CommitsUpdaterQueue( m_update_commits_queue );
  }
}

void CommitBrowser::OnUpdateComplete( wxCommandEvent& ) {
  if( m_updater == 0 ) {
    return;
  }
  m_updater->Wait();
  if( m_updater->m_what == _T( "BRANCHES" ) ) {
    if( m_updater->m_branches.GetCount() == 0 ) {
      delete m_updater;
      m_updater = 0;
      return;
    }
    for( unsigned int i = 0; i < m_updater->m_branches.GetCount(); ++i ) {
      Choice1->Append( m_updater->m_branches[i] );
    }
    Choice1->Select( 0 );
    CommitsUpdaterQueue( _T( "COMMITS:" ) + m_updater->m_branches[0] );
  } else if( m_updater->m_what.StartsWith( _T( "DETAIL:" ) ) ) {
    wxString commit = m_updater->m_what.AfterFirst( _T( ':' ) );
    TextCtrl1->Clear();
    TextCtrl1->SetValue( m_updater->m_detailed_commit_log );
  }
  delete m_updater;
  m_updater = 0;
  if( m_update_queue != wxEmptyString ) {
    m_updater = new CommitUpdater( this, m_repo_path, m_repo_type );
    m_updater->Update( m_update_queue );
    m_update_queue = wxEmptyString;
  }
}
